
`include "common_header.verilog"

//  *************************************************************************
//  File : p8264_deskew_buff.vhd
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2010 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Denis Poverennyy
//  info@morethanip.com
//  *************************************************************************
//  Description : The p8264_deskew_buff module is a set of Deskew buffers 
//  (one block  per lane. Parameters allow to set different configuration for 
//  subset of buffers0/1 and buffers0/1               
//  Version     : $Id: p8264_deskew_buff.v,v 1.4 2014/12/16 13:30:26 dk Exp $
//  *************************************************************************


module p8264_deskew_buff (

        reset_rxclk,
        cgmii_rxclk,
        desk_buf_rst_rd,
        desk_buf_rst_wr,
        desk_buf_data_0,
        desk_buf_data_1,
        desk_buf_data_2,
        desk_buf_data_3,
        desk_buf_rd,
        desk_buf_full,
        desk_buf_aempty,
        desk_buf_empty,
        reset_sd_rx_clk,
        sd_rx_clk,
        pcs_block_0,
        pcs_block_1,
        pcs_block_2,
        pcs_block_3,
        desk_buf_wr);



parameter AE_THRESHOLD_01 = 3;
parameter AE_THRESHOLD_23 = 3;
parameter DESKEW_WIDTH_01 = 66;
parameter DESKEW_WIDTH_23 = 66;
parameter DESKEW_FIFO_01  = 64;
parameter DESKEW_FIFO_23  = 64;
parameter DESKEW_ADDR_01  = 6;
parameter DESKEW_ADDR_23  = 6;

input                           reset_rxclk;            // async active
input                           cgmii_rxclk;            // Reference clock
input   [3:0]                   reset_sd_rx_clk;        // async active high reset
input   [3:0]                   sd_rx_clk;              // Serdes clock
input   [3:0]                   desk_buf_rst_rd;        // buffer reset in the core clock domain
input   [3:0]                   desk_buf_rst_wr;        // buffer reset in the serdes clock domains
output  [DESKEW_WIDTH_01 -1:0]  desk_buf_data_0;        // 66 block data plus block sync or FEC91 data
output  [DESKEW_WIDTH_01 -1:0]  desk_buf_data_1;        // 66 block data plus block sync or FEC91 data        
output  [DESKEW_WIDTH_23 -1:0]  desk_buf_data_2;        // 66 block data plus block sync
output  [DESKEW_WIDTH_23 -1:0]  desk_buf_data_3;        // 66 block data plus block sync         
input   [3:0]                   desk_buf_rd;            // read enable 
output  [3:0]                   desk_buf_full;          // If high, the Deskew Buffer is in overflow state - read too slow
output  [3:0]                   desk_buf_aempty;        // if low, data is available in the Deskew Buffer
output  [3:0]                   desk_buf_empty;         // if low, data is available in the Deskew Buffer
input   [DESKEW_WIDTH_01 -1:0]  pcs_block_0;            // 66 block data  plus block sync or FEC91 data
input   [DESKEW_WIDTH_01 -1:0]  pcs_block_1;            // 66 block data  plus block sync or FEC91 data
input   [DESKEW_WIDTH_23 -1:0]  pcs_block_2;            // 66 block data  plus block sync
input   [DESKEW_WIDTH_23 -1:0]  pcs_block_3;            // 66 block data  plus block sync
input   [3:0]                   desk_buf_wr;            // write enable 


//------------------------------------------------------
//              Output Signals
//------------------------------------------------------

wire    [DESKEW_WIDTH_01 -1:0]  desk_buf_data_0;        
wire    [DESKEW_WIDTH_01 -1:0]  desk_buf_data_1;        
wire    [DESKEW_WIDTH_23 -1:0]  desk_buf_data_2;        
wire    [DESKEW_WIDTH_23 -1:0]  desk_buf_data_3;        
wire    [3:0]                   desk_buf_full;          
wire    [3:0]                   desk_buf_aempty;        
wire    [3:0]                   desk_buf_empty;         


//------------------------------------------------------
//              Internal Signals
//------------------------------------------------------

wire    [DESKEW_WIDTH_01*2 + DESKEW_WIDTH_23*2 - 1:0] pcs_block;
wire    [DESKEW_WIDTH_01*2 + DESKEW_WIDTH_23*2 - 1:0] desk_buf_data;
wire    [3:0]   desk_buf_full_sd;                       // buffer full in serdes clock domain
wire    [3:0]   desk_buf_full_sd_latch;                 // set to 1, if full flag is asserted,
                                                        // only reset cleares the bit


assign pcs_block = {pcs_block_3, pcs_block_2, pcs_block_1, pcs_block_0};
assign {desk_buf_data_3, desk_buf_data_2, desk_buf_data_1, desk_buf_data_0} = desk_buf_data; 


genvar i_01;
generate for(i_01=0; i_01< 2; i_01=i_01+1)
begin:gen_i_01

r_fifo_1234_wl #(

          .FF_WIDTH(DESKEW_WIDTH_01),
          .ADDR_WIDTH(DESKEW_ADDR_01),
          .DEPTH(DESKEW_FIFO_01),
          .AF_THRESHOLD(3),
          .AE_THRESHOLD(AE_THRESHOLD_01) 

          )

        U_DESKEW_BUFF_01 ( 

          .reset_wclk   (reset_sd_rx_clk[i_01]),
          .reset_rclk   (reset_rxclk),
          .sw_reset_wclk(desk_buf_rst_wr[i_01]),
          .sw_reset_rclk(desk_buf_rst_rd[i_01]),
          .wclk         (sd_rx_clk[i_01]),
          .wren         (desk_buf_wr[i_01]),
          .din          (pcs_block[(DESKEW_WIDTH_01*i_01 + DESKEW_WIDTH_01- 1):DESKEW_WIDTH_01*i_01]),
          .rclk         (cgmii_rxclk),
          .rden         (desk_buf_rd[i_01]),
        `ifdef MTIPSDPM_GEN_READEN
          .mem_rden     (desk_buf_rd[i_01]),
        `endif
          .dout         (desk_buf_data[(DESKEW_WIDTH_01*i_01 + DESKEW_WIDTH_01- 1):DESKEW_WIDTH_01*i_01]),
          .full         (desk_buf_full_sd[i_01]),
          .afull        (),
          .empty        (desk_buf_empty[i_01]),
          .aempty       (desk_buf_aempty[i_01]),
          .wlevel       ());
end
endgenerate

genvar i_23;
generate for(i_23=2; i_23< 4; i_23=i_23+1)
begin:gen_i_23

r_fifo_1234_wl #(

          .FF_WIDTH(DESKEW_WIDTH_23),
          .ADDR_WIDTH(DESKEW_ADDR_23),
          .DEPTH(DESKEW_FIFO_23),
          .AF_THRESHOLD(3),
          .AE_THRESHOLD(AE_THRESHOLD_23) 

          )

        U_DESKEW_BUFF_23 ( 

          .reset_wclk   (reset_sd_rx_clk[i_23]),
          .reset_rclk   (reset_rxclk),
          .sw_reset_wclk(desk_buf_rst_wr[i_23]),
          .sw_reset_rclk(desk_buf_rst_rd[i_23]),
          .wclk         (sd_rx_clk[i_23]),
          .wren         (desk_buf_wr[i_23]),
          .din          (pcs_block[(DESKEW_WIDTH_01*2 + DESKEW_WIDTH_23*(i_23-2) + DESKEW_WIDTH_23- 1):(DESKEW_WIDTH_01*2 + DESKEW_WIDTH_23*(i_23-2))]),
          .rclk         (cgmii_rxclk),
          .rden         (desk_buf_rd[i_23]),
        `ifdef MTIPSDPM_GEN_READEN
          .mem_rden     (desk_buf_rd[i_23]),
        `endif
          .dout         (desk_buf_data[(DESKEW_WIDTH_01*2 + DESKEW_WIDTH_23*(i_23-2) + DESKEW_WIDTH_23- 1):(DESKEW_WIDTH_01*2 + DESKEW_WIDTH_23*(i_23-2))]),
          .full         (desk_buf_full_sd[i_23]),
          .afull        (),
          .empty        (desk_buf_empty[i_23]),
          .aempty       (desk_buf_aempty[i_23]),
          .wlevel       ());
end
endgenerate




// Deskew buffer_full flag latching:
genvar gv;
generate for(gv=0; gv < 4; gv = gv+1)
begin:gen_full


p8264_latch U_FULL_LATCH(

        .reset_clk              (reset_sd_rx_clk[gv]),
        .clk                    (sd_rx_clk[gv]),
        .latch_reset_sync       (desk_buf_rst_wr[gv]),
        .latch_set              (desk_buf_full_sd[gv]),
        .latched                (desk_buf_full_sd_latch[gv])
                                                                );


mtip_xsync #(1) U_BUFF_FULL_SYNC (

        .data_in        (desk_buf_full_sd_latch[gv]),
        .reset          (reset_rxclk),
        .clk            (cgmii_rxclk),
        .data_s         (desk_buf_full[gv]));
end
endgenerate

endmodule // module p8264_deskew_buff